﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Google.GData.Photos;
using Google.GData.Client;
using System.Xml;
using Google.GData.Extensions;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Net;

namespace PicasaHelper
{
	class Program
	{
		static string ReplaceAll(string toBeReplacedString, string oldString, string newString)
		{
			while (toBeReplacedString.IndexOf(oldString) >= 0)
				toBeReplacedString = toBeReplacedString.Replace(oldString, newString);
			return toBeReplacedString;
		}
		static string ReadFromFile(string fn)
		{
			return ReadFromFile(fn, Encoding.Default);
		}
		static string ReadFromFile(string fn, Encoding encoding)
		{
			string ret = "";
			using (StreamReader sr = new StreamReader(fn, encoding))
			{
				ret = sr.ReadToEnd();
			}
			return ret;
		}
		static void WriteToFile(string fn, string content, Encoding enc)
		{
			using (StreamWriter sw = new StreamWriter(fn, false, enc))
				sw.Write(content);
		}
		static void Main(string[] args)
		{
            if (args.Length == 0)
            {
                Assembly a = Assembly.GetExecutingAssembly();
                Stream strHelp = a.GetManifestResourceStream(typeof(Program).Namespace + ".Help.txt");
                using (StreamReader sr = new StreamReader(strHelp))
                {
                    Console.Write(sr.ReadToEnd());
                }
                Environment.Exit(0);
            }

            #region buildSummaryAlbum
            if (args[0] == "buildSummaryAlbum")
            {
                Dictionary<string, string> argDic = Global.Global.convertArgs(args);

                PicasaService service = null;

                string summaryAlbumTitle=argDic["t"];
                string username = argDic["a"];

                #region login
                Console.Write("Try to login...");
                try
                {
                    service = createPicasaService(username, argDic["p"]);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("fail");
                    Console.WriteLine(ex.Message);
                    Console.WriteLine(ex.StackTrace);
                    return;
                }
                Console.WriteLine("success"); 
                #endregion

                PicasaEntry summaryAlbumEntry = null;

                #region find the album


                Console.Write("Finding album '"+summaryAlbumTitle+"'");

                AlbumQuery albumQuery = new AlbumQuery(PicasaQuery.CreatePicasaUri(username));
                
                PicasaFeed albumFeed = service.Query(albumQuery);

                foreach (PicasaEntry albumEntry in albumFeed.Entries)
                {
                    Console.Write(".");
                    if (albumEntry.Title.Text == summaryAlbumTitle)
                    {
                        Console.WriteLine("Found");
                        summaryAlbumEntry = albumEntry;

                        break;
                    }
                }

                if (summaryAlbumEntry == null)
                {
                    Console.WriteLine("Can't find. Creating new...");

                    summaryAlbumEntry = new AlbumEntry();
                    summaryAlbumEntry.Title.Text = summaryAlbumTitle;
                    summaryAlbumEntry.Summary.Text = "Summary Album by AL [Exclude From Picasa Summary Maker]";

                    Uri feedUri = new Uri(PicasaQuery.CreatePicasaUri(username));

                    summaryAlbumEntry = (PicasaEntry)service.Insert(feedUri, summaryAlbumEntry);
                }
                #endregion

                #region get existed photo list

                PhotoQuery photoQuery = new PhotoQuery(summaryAlbumEntry.FeedUri);

                PicasaFeed photoFeed = service.Query(photoQuery);

                #endregion

                #region process source
                XmlDocument doc=new XmlDocument();
                doc.Load(argDic["s"]);


				foreach (XmlElement accountNode in doc.GetElementsByTagName("PicasaAccount"))
				{
					#region process each account
					string sourceAccountName=accountNode.GetAttribute("account");


					int processingAlbumIndex = 0;
					XmlNodeList albumNodeList= accountNode.GetElementsByTagName("Album");
					foreach (XmlElement albumNode in albumNodeList)
					{
						processingAlbumIndex++;
						
						#region process each album
						string albumTitle = albumNode.GetAttribute("title");

						string summaryText=albumNode.GetAttribute("summary");
						if (summaryText != null && summaryText.IndexOf("[Exclude From Picasa Summary Maker]") >= 0)
						{
							continue;
						}

						Console.Write("\t{0}/{1}:{2}",processingAlbumIndex ,albumNodeList.Count, albumTitle);

						#region try to find the old item in the summary album, if found, delete it.
						foreach (PicasaEntry entry in photoFeed.Entries)
						{
							if (entry.Title.Text == albumTitle)
							{
								Console.Write("found,Deleting.");
								entry.Delete();
							}
						}
						Console.WriteLine();
						#endregion

						#region create new photo

						#region download album thumb to local file
						Console.Write("\tDownloading thumbnail...");

						WebClient wc = new WebClient();

						string localFileName = Path.GetTempFileName() + ".jpg";
						try
						{
							wc.DownloadFile(albumNode.GetAttribute("thumbnail.url"), localFileName);
						}
						catch (WebException)
						{
							File.Delete(localFileName);
							Console.WriteLine("Fail");
							continue;
						}
						Console.WriteLine("OK.");

						#endregion
						Console.Write("\tInsert into summary album...");
						Uri postUri = new Uri(summaryAlbumEntry.FeedUri);

						System.IO.FileInfo fileInfo = new System.IO.FileInfo(localFileName);
						System.IO.FileStream fileStream = fileInfo.OpenRead();

						PicasaEntry insertedPhotoEntry = (PicasaEntry)service.Insert(postUri, fileStream, "image/jpeg", localFileName);

						fileStream.Close();

						File.Delete(localFileName);

						Console.WriteLine("ok.");

						#endregion

						#region update photo entry info
						Console.Write("\tUpdating info...");

						DateTime date = new DateTime();

						string dateRemovedStr;
						if (!Global.Global.parseHeadDate(albumTitle, out dateRemovedStr, ref date))
							if (!DateTime.TryParse(albumNode.GetAttribute("published"), out date))
								DateTime.TryParse(albumNode.GetAttribute("updated"), out date);

						insertedPhotoEntry.Title.Text = albumTitle;
                        insertedPhotoEntry.Summary.Text = albumTitle + " [ " + albumNode.GetAttribute("picasaUrl")+" ]";

						insertedPhotoEntry.Updated = insertedPhotoEntry.Published = date;
						

						insertedPhotoEntry.Update();

						Console.WriteLine("ok.");
						#endregion

						#region add comment
						Console.Write("\tAdd comment...");
						{
							CommentEntry toInsertCommentEntry = new CommentEntry();
							StringBuilder sbComment = new StringBuilder();
							sbComment.AppendLine(string.Format("View all {0} pic(s):{1}", albumNode.GetAttribute("numphotos"),albumNode.GetAttribute("picasaUrl")));
							sbComment.AppendLine("From " + sourceAccountName);

							toInsertCommentEntry.Content.Content = sbComment.ToString();
							int retryCount = 0;
							bool insertSuccessed = false;

							while (!insertSuccessed)
							{
								try
								{
									PicasaEntry createdCommentEntry = (PicasaEntry)service.Insert(new Uri(insertedPhotoEntry.FeedUri), toInsertCommentEntry);
									insertSuccessed = true;
								}
								catch (GDataRequestException)
								{
									if (retryCount++ > 10)
									{
										Console.WriteLine("postSummaryToAccount: insert comment error after 10 retrys");
										break;
									}
								}
							}
						}
						Console.WriteLine("OK");
						#endregion
						#endregion
					} 
					#endregion
				}



                #endregion

            }
            #endregion

			#region getFreeSpace
			if (args[0] == "getFreeSpace")
			{
				Dictionary<string, string> argDic = Global.Global.convertArgs(args);

				PicasaService service = null;

				string username = argDic["a"];

				#region login
				Console.Write("Try to login...");
				try
				{
					service = createPicasaService(username, argDic["p"]);
				}
				catch (Exception ex)
				{
					Console.WriteLine("fail");
					Console.WriteLine(ex.Message);
					Console.WriteLine(ex.StackTrace);
					return;
				}
				
				Console.WriteLine("success");
				#endregion

				PicasaQuery query = new PicasaQuery("http://picasaweb.google.com/data/feed/api/user/default");
				
				PicasaFeed feed;
				try
				{
					feed = service.Query(query) as PicasaFeed;
				}
				catch(Exception ex){
					Console.WriteLine("Failed query feed : "+ex.Message);
					return;
				}

				int quotalimit = 0,quotacurrent=0;
				foreach (IExtensionElementFactory elementFactory in feed.ExtensionElements)
				{
					if(elementFactory.XmlName=="quotalimit")
					{
						quotalimit = (elementFactory as GPhotoQuotaLimit).IntegerValue;
						continue;
					}
					if(elementFactory.XmlName=="quotacurrent")
					{
						quotacurrent = (elementFactory as GPhotoQuotaCurrent).IntegerValue;
						continue;
					}
				}

				Console.WriteLine("quotalimit:" + quotalimit);
				Console.WriteLine("quotacurrent:" + quotacurrent);

			}
			#endregion

			#region buildRSS

			if (args[0] == "buildRSS")
			{
				string bodyTemplateFilePath = args[1];
				string itemTemplateFilePath = args[2];
				string dataSource = args[3];
				string outputFile = args[4];


				string[] inputLines = ReadFromFile(dataSource, Encoding.Default).Split('\n');
				string bodyTemplate = ReadFromFile(bodyTemplateFilePath);
				string itemTemplate = ReadFromFile(itemTemplateFilePath);

				StringBuilder sbItemsContext = new StringBuilder();
				foreach (string line in inputLines)
				{
					string[] items = line.Split('\t');

					if (items.Length <= 1)
						continue;

					if (items.Length > 5 && Regex.Unescape(items[5]).IndexOf("[Exclude From Picasa Summary Maker]") >= 0)
						continue;

					string itemContext = itemTemplate;

					for (int i = 0; i < items.Length; i++)
						itemContext = ReplaceAll(itemContext, "[[" + i + "]]", items[i]);

					sbItemsContext.AppendLine(itemContext);
				}

				WriteToFile(
					outputFile,
					bodyTemplate.Replace("<!--[Items]-->", sbItemsContext.ToString()),
					Encoding.UTF8
					);
#if true

#else

				using (XmlTextWriter xtw = new XmlTextWriter(Console.Out))
				{

					xtw.Formatting = Formatting.Indented;
					xtw.WriteStartDocument();

					xtw.WriteStartElement("rss");
					xtw.WriteAttributeString("xmlns:atom", "http://www.w3.org/2005/Atom");
					xtw.WriteAttributeString("xmlns:openSearch", "http://a9.com/-/spec/opensearchrss/1.0/");
					xtw.WriteAttributeString("xmlns:exif", "http://schemas.google.com/photos/exif/2007");
					xtw.WriteAttributeString("xmlns:geo", "http://www.w3.org/2003/01/geo/wgs84_pos#");
					xtw.WriteAttributeString("xmlns:gml", "http://www.opengis.net/gml");
					xtw.WriteAttributeString("xmlns:georss", "http://www.georss.org/georss");
					xtw.WriteAttributeString("xmlns:photo", "http://www.pheed.com/pheed/");
					xtw.WriteAttributeString("xmlns:media", "http://search.yahoo.com/mrss/");
					xtw.WriteAttributeString("xmlns:batch", "http://schemas.google.com/gdata/batch");
					xtw.WriteAttributeString("xmlns:gphoto", "http://schemas.google.com/photos/2007");
					xtw.WriteAttributeString("version", "2.0");

					xtw.WriteStartElement("channel");
					xtw.WriteElementString("atom:id", "http://picasaweb.google.com/data/feed/base/user/shiaoal/albumid/5227751755843205473");
					xtw.WriteElementString("lastBuildDate", DateTime.Now.ToString());
					xtw.WriteElementString("title", "Summary");
					xtw.WriteElementString("description", "desc...");

					Random rnd = new Random(Environment.TickCount);

					foreach (string line in inputLines)
					{
						string[] items = line.Split(new char[] { '\t' });
						if (items.Length < 5) continue;
				#region item
						xtw.WriteStartElement("item");

						xtw.WriteStartElement("guid");
						xtw.WriteAttributeString("isPermaLink", "false");
						xtw.WriteString(items[2] + rnd.Next().ToString());
						xtw.WriteEndElement();

						xtw.WriteElementString("pubDate", items[4]);

						xtw.WriteElementString("title", items[0]);

						xtw.WriteElementString("link", items[2]);

				#region mdeia:group
						xtw.WriteStartElement("media:group");

						xtw.WriteStartElement("media:title");
						xtw.WriteAttributeString("type", "plain");
						xtw.WriteString(items[0]);
						xtw.WriteEndElement();


						xtw.WriteStartElement("media:description");
						xtw.WriteAttributeString("type", "plain");
						xtw.WriteString(items[0]);
						xtw.WriteEndElement();

						xtw.WriteStartElement("media:content");
						xtw.WriteAttributeString("url", items[1]);
						xtw.WriteAttributeString("height", "1200");
						xtw.WriteAttributeString("width", "1600");
						xtw.WriteAttributeString("type", "image/jpeg");
						xtw.WriteAttributeString("medium", "image");
						xtw.WriteEndElement();

						xtw.WriteStartElement("media:thumbnail");
						xtw.WriteAttributeString("url", items[1]);
						xtw.WriteAttributeString("height", "54");
						xtw.WriteAttributeString("width", "54");
						xtw.WriteEndElement();

						xtw.WriteEndElement();
				#endregion
						xtw.WriteEndElement();
				#endregion
					}
					xtw.WriteEndElement();
					xtw.WriteEndElement();
					xtw.WriteEndDocument();
				}

#endif
			}

			#endregion

			#region dumpAlbumXML
			//format: dumpAlbumXML /a account /p password /o outputXML_Name /level {account|album|photo}
			if (args[0] == "dumpAlbumXML")
			{
				Dictionary<string, string> argDic = Global.Global.convertArgs(args);

				#region handle dump level
				int dumpLevel = 0;

				if (argDic.ContainsKey("level"))
				{
					string[]levelMap={"account","album","photo"};
					for(int i=0;i<levelMap.Length;i++)
						if (argDic["level"] == levelMap[i])
						{
							dumpLevel = i;
							break;
						}
				}
				#endregion

				using (XmlTextWriter xtw = new XmlTextWriter(argDic["o"], Encoding.UTF8))
				{
					xtw.Formatting = Formatting.Indented;
					xtw.WriteStartDocument();

					xtw.WriteStartElement("PicasaAccount");

					Console.Write("Try to login...");
					PicasaService service =null;

					try
					{
						service = createPicasaService(argDic["a"], argDic["p"]);
					}
					catch (Exception ex)
					{
						Console.WriteLine(ex.Message);
						Console.WriteLine(ex.StackTrace);
					}
					if (service == null)
					{
						Console.WriteLine("Can't login. exit...");
						return;
					}
					Console.WriteLine("ok");
					xtw.WriteAttributeString("account", argDic["a"]);
					xtw.WriteAttributeString("password", argDic["p"]);
					#region album level
					if (dumpLevel >= 1)
					{
						xtw.WriteStartElement("Albums");

						Console.WriteLine("Query albums");
						AlbumQuery albumQuery = new AlbumQuery(PicasaQuery.CreatePicasaUri(argDic["a"]));
						PicasaFeed albumFeed = null;
						try
						{
							albumFeed = service.Query(albumQuery);
						}
						catch (Exception ex)
						{
							Console.WriteLine(ex.Message);
							Console.WriteLine(ex.StackTrace);
						}
						if (albumFeed == null)
						{
							Console.WriteLine("query fail, exit");
							Environment.Exit(1);
						}

						#region handle each album
						foreach (PicasaEntry albumEntry in albumFeed.Entries)
						{
							Console.WriteLine("Album:" + albumEntry.Title.Text);

							xtw.WriteStartElement("Album");

                            xtw.WriteAttributeString("title", albumEntry.Title.Text);

							xtw.WriteAttributeString("numphotos", albumEntry.GetPhotoExtensionValue("numphotos"));

							xtw.WriteAttributeString("updated", albumEntry.Updated.ToString());

							xtw.WriteAttributeString("published", albumEntry.Published.ToString());

							xtw.WriteAttributeString("picasaUrl", albumEntry.AlternateUri.Content);

							xtw.WriteAttributeString("feedUri", albumEntry.FeedUri);



							foreach (SimpleElement se in albumEntry.Media.ExtensionElements)
							{
								if (se.XmlName != "thumbnail") continue;
								System.Collections.SortedList sl= se.Attributes;//["url"]
								xtw.WriteAttributeString("thumbnail.url", (string)sl["url"]);
								xtw.WriteAttributeString("thumbnail.size", (string)sl["width"] + "," + (string)sl["height"]);
								
							}

							xtw.WriteAttributeString("summary",albumEntry.Summary.Text);


							#region picture level
							if (dumpLevel >= 2)
							{
								xtw.WriteStartElement("Photos");
								string uri = PicasaQuery.CreatePicasaUri(argDic["a"], albumEntry.Title.Text);
								PhotoQuery PhotoQuery = new PhotoQuery(
									albumEntry.Id.AbsoluteUri.Replace("/entry/","/feed/")
									);
								PicasaFeed PhotoFeed = service.Query(PhotoQuery);

								#region handle each photo
								foreach (PicasaEntry photoEntry in PhotoFeed.Entries)
								{
									xtw.WriteStartElement("Photo");

									if (photoEntry.Location!=null)
									{
										xtw.WriteAttributeString("location", photoEntry.Location.Longitude + "," + photoEntry.Location.Latitude);
									}
									xtw.WriteAttributeString("title", photoEntry.Title.Text);
									xtw.WriteAttributeString("content.url", photoEntry.Content.AbsoluteUri.ToString());
									xtw.WriteAttributeString("content.type", photoEntry.Content.Type);
									xtw.WriteAttributeString("updated", photoEntry.Updated.ToString());
									xtw.WriteAttributeString("published", photoEntry.Published.ToString());
                                    xtw.WriteAttributeString("commentCount", photoEntry.GetPhotoExtensionValue("commentCount"));
									xtw.WriteAttributeString("picasaUri", photoEntry.AlternateUri.Content);

									#region size

                                    string w = photoEntry.GetPhotoExtensionValue("width");
                                    string h = photoEntry.GetPhotoExtensionValue("height");
									if (w != null && h != null)
									{
										xtw.WriteAttributeString("size", w + "," + h);
									}
									#endregion

									#region timestamp
                                    string t = photoEntry.GetPhotoExtensionValue("timestamp");
									if (t != null)
									{
										double ms = double.Parse(t);
										DateTime realTime = new DateTime(1970, 1, 1).AddMilliseconds(ms);
										xtw.WriteAttributeString("timestamp", realTime.ToString());
									}
									#endregion
									//photoEntry.SaveToXml(xtw);


									#region thumbnail
									xtw.WriteStartElement("Thumbnails");

									foreach (SimpleElement se in photoEntry.Media.ExtensionElements)
									{
										if (se.XmlName != "thumbnail") continue;

										xtw.WriteStartElement("Thumbnail");
										System.Collections.SortedList sl = se.Attributes;//["url"]
										xtw.WriteAttributeString("url", (string)sl["url"]);
										xtw.WriteAttributeString("size", (string)sl["width"] + "," + (string)sl["height"]);
										xtw.WriteEndElement();
									}

									xtw.WriteEndElement();
									#endregion
									xtw.WriteEndElement();
								}
								#endregion

								xtw.WriteEndElement();
							}
							#endregion

							xtw.WriteEndElement();

						}
						#endregion

						xtw.WriteEndElement();
					} 
					#endregion
					xtw.WriteEndElement();
					xtw.WriteEndDocument();
				}

			}
			#endregion

			#region dumpAlbums

			//format: dumpAlbums account password
			if (args[0] == "dumpAlbums")
			{
				try
				{
					string account = args[1];
					string password = args[2];
					PicasaService service = createPicasaService(account, password);
					AlbumQuery query = new AlbumQuery(PicasaQuery.CreatePicasaUri(account));
					PicasaFeed feed = service.Query(query);
					#region handle each album
					foreach (PicasaEntry entry in feed.Entries)
					{
						Console.Write(entry.Title.Text + "\t");

						#region get thumbnail url

						foreach (SimpleElement extensionElement in entry.Media.ExtensionElements)
						{
							if (extensionElement.XmlName != "thumbnail") continue;
							Console.Write((string)extensionElement.Attributes["url"]);
							break;
						}
						Console.Write("\t");

						#endregion

						#region get album link

						foreach (AtomLink link in entry.Links)
						{
							if (link.Rel != "alternate") continue;
							Console.Write(link.AbsoluteUri);
							break;
						}
						Console.Write("\t");
						#endregion

						#region get pic count

						AlbumAccessor ac = new AlbumAccessor(entry);

						Console.Write(ac.NumPhotos + "\t");

						#endregion

						Console.Write(entry.Published + "\t");

						Console.Write(Regex.Escape((entry.Summary.Text)));

						Console.WriteLine();
					}
					#endregion
				}
				catch (Exception)
				{
					Environment.Exit(1);
				}

			}
			#endregion

			#region space
			if (args[0] == "space")
			{
				using (StreamReader sr = new StreamReader(args[1]))
				{
					while (!sr.EndOfStream)
					{
						try
						{
							string[] ss = sr.ReadLine().Split(new char[] { '|' });
							if (ss.Length < 2) continue;
							PicasaService service = createPicasaService(ss[0], ss[1]);
							AlbumQuery query = new AlbumQuery(PicasaQuery.CreatePicasaUri(ss[0]));
							PicasaFeed feed = service.Query(query);
							string lim = null, cur = null;
							foreach (object ab in feed.ExtensionElements)
							{
								GPhotoQuotaLimit ql = ab as GPhotoQuotaLimit;
								if (ql != null)
								{
									lim = ((GPhotoQuotaLimit)ql).Value;
								}
								GPhotoQuotaCurrent qc = ab as GPhotoQuotaCurrent;
								if (qc != null)
								{
									cur = ((GPhotoQuotaCurrent)qc).Value;
								}
							}
							Console.WriteLine(ss[0] + '|' + ss[1] + '|' + cur + '|' + lim);
						}
						catch (Exception)
						{
						}
					}
				}

			}
			#endregion
		}
		static PicasaService createPicasaService(string name, string pw)
		{
			PicasaService myService = new PicasaService("PicasaSummaryMaker");
			myService.setUserCredentials(name + "@gmail.com", pw);
			return myService;
		}

	}
}
